package cool.taomu.toolkit.service.centre.kademlia

import com.google.gson.Gson
import com.google.inject.Inject
import cool.taomu.toolkit.Context
import cool.taomu.toolkit.service.centre.kademlia.service.FindNodeService
import cool.taomu.toolkit.service.centre.kademlia.service.ServiceCentre
import cool.taomu.toolkit.service.kademlia.entity.Constant
import cool.taomu.toolkit.service.kademlia.entity.KPeerNode
import cool.taomu.toolkit.service.kademlia.entity.RequestDto
import cool.taomu.toolkit.service.kademlia.service.ICheckPeer
import cool.taomu.toolkit.service.kademlia.thrift.KademliaService
import cool.taomu.toolkit.service.kademlia.thrift.Node
import cool.taomu.toolkit.service.kademlia.thrift.Response
import cool.taomu.toolkit.service.kademlia.thrift.ServiceEntity
import cool.taomu.toolkit.service.kademlia.utils.BEncodeUtils
import cool.taomu.toolkit.utils.ByteBufferUtils
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.util.List
import org.apache.thrift.TException
import org.eclipse.xtend.lib.annotations.Accessors
import org.slf4j.LoggerFactory

@Accessors
class ServiceCentreImpl implements KademliaService.Iface {

    val static LOG = LoggerFactory.getLogger(ServiceCentreImpl);

    @Inject
    ServiceCentre service

    @Inject
    FindNodeService fNodeService;

    @Inject
    ICheckPeer check

    @Inject
    Context context;

    override findNode(String findNodeId, List<String> excludeIds) throws TException {
        LOG.info("****findNode****:\n{}", findNodeId);
        var res = fNodeService.findNode(findNodeId, excludeIds);
        if (res.isPresent) {
            var nodes = res.get();
            val nodeList = newArrayList();
            nodes.forEach [
                if (!it.host.equalsIgnoreCase("localhost")) {
                    nodeList.add(it)
                }
            ]
            var result = new Gson().toJson(nodeList)
            return new Response(ByteBufferUtils.toByteBuffer(result), 200, "节点集合")
        }
        return new Response(ByteBufferUtils.toByteBuffer(""), 404, "没有找到节点");
    }

    override findValue(String key) throws TException {
        throw new UnsupportedOperationException("TODO: auto-generated method stub")
    }

    override ping(Node node) throws TException {
        LOG.info("****ping****{}");
        LOG.info("{} 发起了ping",node)
        if (node.host.equalsIgnoreCase("localhost")) {
            LOG.info("localhost 无返回值 直接 返回 PONG");
            return new Response(ByteBufferUtils.toByteBuffer("PONG"), 200, "ping结果 localhost 无返回值 直接 返回 PONG");
        }
        var result = service.ping(new KPeerNode(node.host, node.port));
        if (result.isPresent) {
            LOG.info("ping 返回值 :{}", result.get());
            return new Response(ByteBufferUtils.toByteBuffer(result.get()), 200, "ping结果PONG");
        }
        LOG.info("ping无返回值");
        return new Response(ByteBufferUtils.toByteBuffer(""), 404, "ping无返回值");
    }

    override store(String key, String value) throws TException {
        throw new UnsupportedOperationException("TODO: auto-generated method stub")
    }

    override findService(ServiceEntity message) throws TException {
        LOG.info("****findService****\n{}", message);
        var dto = new RequestDto();
        dto.serviceName = message.serviceName;
        dto.method = message.method;
        dto.params = message.params;
        dto.contentType = message.contentType;
        dto.cookie = message.cookie
        dto.body = message.body;
        var res = service.callService(dto);
        if (res.isPresent) {
            var result = res.get();
            return new Response(ByteBufferUtils.toByteBuffer(result), 200, "返回结果");
        }
        return new Response(ByteBufferUtils.toByteBuffer("[]"), 404, "没有结果");
    }

    override findServiceNode(ServiceEntity message, List<String> excludeIds) throws TException {
        LOG.info("****findServiceNode****:\n{}", message);
        var dto = new RequestDto();
        dto.serviceName = message.serviceName;
        dto.method = message.method;
        dto.params = message.params;
        dto.contentType = message.contentType;
        dto.cookie = message.cookie
        dto.body = message.body;
        var res = service.findServiceNode(dto, excludeIds);
        if (res.isPresent) {
            var nodes = res.get();
            val nodeList = newArrayList();
            nodes.forEach [
                nodeList.add(it)
            ]
            LOG.info("返回找到的服务节点")
            var result = new Gson().toJson(nodeList)
            return new Response(ByteBufferUtils.toByteBuffer(result), 200, "节点集合");
        }
        LOG.info("返回没有找到的服务节点")
        return new Response(ByteBufferUtils.toByteBuffer("[]"), 404, "没有节点集合");
    }

    override downloadFile(String infoHash, long offset, long length) throws TException {
        LOG.info("****downloadFile****:\n{}", infoHash)
        var storagePath = Constant.TORRENT_DOWNLOAD_PATH
        var file = new File(storagePath, infoHash);

        if (!file.exists()) {
            var Response response = new Response();
            response.setStatus(404);
            LOG.info("下载的文件不存在")
            response.setMessage("download file not found");
            return response;
        }

        try (var  raf = new RandomAccessFile(file, "r")) {
            raf.seek(offset);
            var buffer = newByteArrayOfSize(Math.min(length, Integer.MAX_VALUE) as int)
            var int bytesRead = raf.read(buffer);

            var Response response = new Response();
            if (bytesRead > 0) {
                var actualData = newByteArrayOfSize(bytesRead);
                System.arraycopy(buffer, 0, actualData, 0, bytesRead);
                response.setData(ByteBuffer.wrap(actualData));
                response.setStatus(200);
                response.setMessage("OK");
            } else {
                response.setStatus(400);
                LOG.info("End of file reached")
                response.setMessage("End of file reached");
            }
            return response;
        } catch (Exception e) {
            throw new TException("Error reading torrent file", e);
        }
    }

    override getFileSize(String infoHash) throws TException {
        var storagePath = Constant.TORRENT_DOWNLOAD_PATH
        var file = new File(storagePath, infoHash);

        if (!file.exists()) {
            return new Response(ByteBufferUtils.toByteBuffer("0"), 404, #["没有文件: ", infoHash].join());
        }
        return new Response(ByteBufferUtils.toByteBuffer(Long.toString(file.length())), 200, "返回文件大小");
    }

    override getFileLastModifiedTime(String infoHash) throws TException {
        var storagePath = Constant.TORRENT_DOWNLOAD_PATH
        var file = new File(storagePath, infoHash);
        if (!file.exists()) {
            return new Response(ByteBufferUtils.toByteBuffer("0"), 404, #["没有文件: ", infoHash].join());
        }
        var hash = BEncodeUtils.read(file.absolutePath)
        var lastModified = Long.toString(hash.get("creation date") as Long);
        return new Response(ByteBufferUtils.toByteBuffer(lastModified), 200, "返回最后修改时间，单位为毫秒");
    }

}
